boto3でIoT CoreのATSエンドポイントに接続する(SSL validation failedエラー対応)
最近、boto3でIoT Coreにアクセスすると、SSL validation failed
エラーになる事があります。応急処置は下記ブログで紹介されていますが、本記事では根本対応をご紹介します。
環境
ライブラリ | バージョン |
---|---|
boto3 | 1.16.31 |
botocore | 1.19.31 |
certifi | 2020.12.05 |
SSL validation failedエラーが発生する
たとえば、boto3でIoT Coreにアクセスすると、SSL validation failed
が発生します。
下記は、LambdaからIoT CoreのデバイスシャドウをGetする際のエラーメッセージです。
{ "errorMessage": "SSL validation failed for https://data.iot.ap-northeast-1.amazonaws.com/things/led-device/shadow [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1091)", "errorType": "SSLError", "stackTrace": [ " File \"/var/task/lambda_function.py\", line 18, in lambda_handler\n res = iot_data.get_thing_shadow(thingName='led-device')\n", " File \"/var/runtime/botocore/client.py\", line 357, in _api_call\n return self._make_api_call(operation_name, kwargs)\n", " File \"/var/runtime/botocore/client.py\", line 663, in _make_api_call\n operation_model, request_dict, request_context)\n", " File \"/var/runtime/botocore/client.py\", line 682, in _make_request\n return self._endpoint.make_request(operation_model, request_dict)\n", " File \"/var/runtime/botocore/endpoint.py\", line 102, in make_request\n return self._send_request(request_dict, operation_model)\n", " File \"/var/runtime/botocore/endpoint.py\", line 137, in _send_request\n success_response, exception):\n", " File \"/var/runtime/botocore/endpoint.py\", line 256, in _needs_retry\n caught_exception=caught_exception, request_dict=request_dict)\n", " File \"/var/runtime/botocore/hooks.py\", line 356, in emit\n return self._emitter.emit(aliased_event_name, **kwargs)\n", " File \"/var/runtime/botocore/hooks.py\", line 228, in emit\n return self._emit(event_name, kwargs)\n", " File \"/var/runtime/botocore/hooks.py\", line 211, in _emit\n response = handler(**kwargs)\n", " File \"/var/runtime/botocore/retryhandler.py\", line 183, in __call__\n if self._checker(attempts, response, caught_exception):\n", " File \"/var/runtime/botocore/retryhandler.py\", line 251, in __call__\n caught_exception)\n", " File \"/var/runtime/botocore/retryhandler.py\", line 277, in _should_retry\n return self._checker(attempt_number, response, caught_exception)\n", " File \"/var/runtime/botocore/retryhandler.py\", line 317, in __call__\n caught_exception)\n", " File \"/var/runtime/botocore/retryhandler.py\", line 223, in __call__\n attempt_number, caught_exception)\n", " File \"/var/runtime/botocore/retryhandler.py\", line 359, in _check_caught_exception\n raise caught_exception\n", " File \"/var/runtime/botocore/endpoint.py\", line 200, in _do_get_response\n http_response = self._send(request)\n", " File \"/var/runtime/botocore/endpoint.py\", line 269, in _send\n return self.http_session.send(request)\n", " File \"/var/runtime/botocore/httpsession.py\", line 281, in send\n raise SSLError(endpoint_url=request.url, error=e)\n" ] }
Lambdaコード例
import boto3 iot_data = boto3.client('iot-data') def lambda_handler(event, context): res = iot_data.get_thing_shadow(thingName='led-device') print(res)
原因
botocoreが使っているcertifiにおいて、バージョンが2020.11.08から2020.12.05になるとき、Symantec社のルートCA証明書が削除されているためです。 Symantec社の認証局無効化については以前にいろいろ発表されており、certifiが今回その対応をしたことによるものですね。
対応方法:ATSエンドポイントにアクセスする
IoT CoreのATSエンドポイントを使って、アクセスするように修正します。
ATSエンドポイントを取得する
いずれかの方法で取得できます。
- IoT Coreの設定画面でATSエンドポイントを取得する
- AWS CLIコマンドでATSエンドポイントを取得する
IoT Coreの設定画面でATSエンドポイントを取得する
ブラウザでIoT Coreにアクセスし、「設定」にある「カスタムエンドポイント」を使います。
AWS CLIコマンドでATSエンドポイントを取得する
下記コマンドを実行します。
$ aws iot describe-endpoint --endpoint-type iot:Data-ATS { "endpointAddress": "xxxxxx-ats.iot.ap-northeast-1.amazonaws.com" }
boto3でIoT CoreのATSエンドポイントに接続する
boto3.client
のendpoint_url
でATSエンドポイントを明示すればOKです。https://
の付与も忘れないでください。
import boto3 iot_data = boto3.client('iot-data', endpoint_url='https://xxxxxx-ats.iot.ap-northeast-1.amazonaws.com') def lambda_handler(event, context): res = iot_data.get_thing_shadow(thingName='led-device') print(res)
さいごに
ATSエンドポイントが推奨されていることは知っていましたが、「boto3の接続時にATSエンドポイントを明示すること」は盲点でした。 困っている方の参考になれば幸いです。